Histogram Equalization

Transforms an image with an arbitrary histogram to one with a flat histogram

Discrete Implementation

Proof of continuous version:

g(f)=fminfpF(t)dtpG(g)=pF(f)|dgdf|,g(0,1)dgdf=pF(f)pG(g)=1,g(0,1)\begin{align*} g(f) = \int_{f_\min}^f p_F (t) dt \\ p_G (g) = \frac{p_F(f)}{|\frac{dg}{df}|}, \, g \in (0,1) \\ \frac{dg}{df} = p_F(f)\\ p_G(g) = 1, \, g \in (0,1) \end{align*}

Example code

Example MATLAB code

function histogram_eq(inimgname)

img=imread(imgname); 
figure; imshow(img); 
[M,N]=size(img);

H=imhist(img); 
H=H/(M*N); 
figure; bar(H);

%Computing the mapping function
for (k=1:256) 
    C(k)=uint8(sum(H(1:k))*255);
end;
% C = uint8(cumsum(H)*255);

figure;plot(C);

%perform mapping
for (i=1:M) 
    for (j=1:N)
        f=double(img(i,j))+1;
        histeqimg(i,j)=C(f); 
    end;
end;

%note the above loop can be replaced by: %histeqimg=C(double(img)+1);  
%this will be much faster!

figure; 
imshow(histeqimg);

Example Python code

import cv2  
import numpy as np  
from matplotlib import pyplot as plt

# read the image using openCV

img = cv2.imread('kid.jpg',0)  
# Calculate the histogram and corresponding bins hist,bins = np.histogram(img.flatten(),256,[0,256])  
# Calculate the cdf and normalize the values to 0-255 cdf = hist.cumsum()  
cdf_normalized = cdf * 255/ cdf[-1]  
# Replace the vales with normalized cdf values img_histeq = cdf_normalized[img]

#display results

fig = plt.figure()  
ax1 = plt.subplot(2,2,1) ax1.get_xaxis().set_visible(False) ax1.get_yaxis().set_visible(False) plt.imshow(img,cmap=plt.cm.gray)  
ax2 = plt.subplot(2,2,2) plt.hist(img.ravel(),256,[0,256])  
ax3 = plt.subplot(2,2,3) ax3.get_xaxis().set_visible(False) ax3.get_yaxis().set_visible(False) plt.imshow(img_histeq,cmap=plt.cm.gray) ax4 = plt.subplot(2,2,4) plt.hist(img_histeq.ravel(),256,[0,256]) plt.show()

Problems with Histogram Equalization

Adaptive histogram equalization

Using non-overlapping blocks to compute the histograms and the mapping function for each block center.

The pixel’s mapping function fs,t(I)f_{s,t}(I) is determined by interpolating the 4 mapping functions of the four block centers

Using blinear weights determined based on its distance to the block centers (s,t),(1s,t),(s,1t),(1s,1t)(s,t), (1-s,t), (s,1-t), (1-s,1-t)

fs,t(I)=(1s)(1t)f00(I)+s(1t)f10(I)+(1s)tf01(I)+stf11(I)f_{s,t}(I)=(1-s)(1-t)f_{00}(I)+s(1-t)f_{10}(I)+(1-s)tf_{01}(I)+stf_{11}(I)


References:

  1. Richard Szeliski, Computer Vision: Algorithms and Applications, 2nd ed. (2022)